<?php
#  Gfanqiang - Software suite for breakthrough GFW
#
#  by Hong Kong Network Institute of Liberty(NIL), licensed under The GNU General Public License v3.0
#  You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.
#  
#  updategc.php - Bootstrap Phase 1
#  "gc" is stand for googleCode. In the old version, we use GAE for update, not GoogleCode.

/* Set Current Directory */
preg_match('/(.*?)\\\updategc\.php$/',__FILE__,$currentdir); 
chdir($currentdir[1]);

/* Define update server*/
$host = "gfangqiang-update.googlecode.com";

require_once("string.inc.php");
require_once("makegservers.inc.php");

echo " Last known good...";
if($lkg=@file_get_contents("data/last-known-good")){
	echo "Exists!\r\n";
	$lkg=explode("\n",str_replace("\r\n","\n",$lkg));
	echo " LAST-KNOWN-GOOD=".implode(",",$lkg)."\r\n";
	foreach($lkg as $value){
		if(($key = array_search($value, $gservers)) !== false) {
			unset($gservers[$key]);
		}
		array_unshift($gservers,$value);
	}
	array_unique($gservers);
}else{
	echo "Not exists!\r\n";
}

/* FUNCTION */
function request($query,$host){
	global $gservers;
	$success=false;
	foreach($gservers as $gkey=>$gserver){ 
		if(! $success){
			echo " Trying\t".$gserver."...";
			$fp = fsockopen('ssl://'.$gserver, 443,$errno,$errstr,3);
			if($fp){
				if ( fwrite($fp, str_replace('{host}',$host,$query)) ) {
					$response=NULL;
					while ( !feof($fp) ) {
						$response .= fgets($fp, 1024);
					}	
					if(preg_match('/HTTP\/1.1 200 OK/',$response)){
						$response=explode("\r\n\r\n",$response);
						unset($response[0]); $response=implode("\r\n\r\n",$response);
						$success=true;
						echo "OK!\r\n";
					}else{
						echo "Walled!\r\n";
						unset($gservers[$gkey]);
					}
				}
				fclose($fp);
			}else{
				echo "Walled!\r\n";
				unset($gservers[$gkey]);
				@fclose($fp);
			}
		} 
	}
	
	return $response;
} 

function update($filename,$hash){
	global $gservers,$host;

	$grabfilename=pathinfo($filename);
	$grabfilename=$grabfilename["dirname"]."/".preg_replace("/^\.%2F/",NULL,urlencode($grabfilename["basename"]));
	$request="GET /svn/trunk/{$grabfilename} HTTP/1.1\r\nHost:{host}\r\nConnection: close\r\n\r\n";
	
	$success=false;
	foreach($gservers as $gkey=>$gserver){ 
		if(! $success){
			echo "Update\t".$filename;
			echo "\t@".$gserver."\t";
			if($fp = fsockopen('ssl://'.$gserver, 443,$errno,$errstr,3)){
				if ( fwrite($fp, str_replace('{host}',$host,$request)) ) {
					$response=NULL;
					while ( !feof($fp) ) {
						$response .= fgets($fp, 1024);
					}
					if(preg_match('/HTTP\/1.1 200 OK/',$response)){
						$response=explode("\r\n\r\n",$response);
						unset($response[0]); $response=implode("\r\n\r\n",$response);
						$success=true;
						echo "OK!\r\n";
					}else{
						echo "Fail!\r\n";
					}
				}
				
				fclose($fp);
			}else{
				echo "Walled!\r\n";
				unset($gservers[$gkey]);
				@fclose($fp);
			}
		}
	}
	
	if(md5($response)==$hash){
		if(dirname($filename)!="." && ! file_exists(dirname($filename))){
			mkdir(dirname($filename),0,true);
		}
		file_put_contents(iconv("utf-8","gb2312",$filename),$response);
	}else{
		echo $str["hash_sign_incorrect"];
		echo $str["anykeytocontinue"];
		echo ">"; fgets(STDIN);
	}

}

/* Load ignore update file list. e.g. Standalone Version */
$ignore=array();
if(file_exists("data/updateignore")){
	$ignore=explode("\n",str_replace("\r\n","\n",file_get_contents("data/updateignore")));
}

/* Check local hash.dat exists */
if(! file_exists("hash.dat")){
	die("Fatal Error: hash.dat not exists!");
}

/* Remote Hash Table */
$query="GET /svn/trunk/sign.dat HTTP/1.1\r\nHost:{host}\r\nConnection: close\r\n\r\n";
echo "Grabbing sign.dat:\r\n";
$sign=request($query,$host);
$sign=base64_decode($sign);

$query="GET /svn/trunk/hash.dat HTTP/1.1\r\nHost:{host}\r\nConnection: close\r\n\r\n";
echo "Grabbing hash.dat:\r\n";
$response=request($query,$host);

if(!file_exists("data/gfq.pubkey")){
	echo $str["cert_notexists"];
	echo $str["anykeytocontinue"];
	echo ">"; fgets(STDIN);
}else{

	if($pubkey=openssl_get_publickey(file_get_contents("data/gfq.pubkey"))){
		while($verify=openssl_verify(md5($response),$sign,$pubkey,OPENSSL_ALGO_MD5)){
			echo "\r\nVerifying signature of hash.dat, result=";
			if($verify == "1"){
				echo "OK!\r\n";
				break;
			}else{
				echo "FAIL!\r\n";
				echo $str["sign_incorrect"];
				echo $str["retryin3seconds"];
				sleep(3);
			}
		}
	}else{
		echo $str["cert_corrupted"];
		echo $str["anykeytocontinue"];
		echo ">"; fgets(STDIN);
	}
}

$response=explode("\r\n",$response);
foreach($response as $value){
	unset($remotefilename,$remotefilehash);
	$value=explode("  ",$value);
	$remotefilehash=$value[0];
	unset($value[0]);
	$remotefilename=implode("  ",$value);
	$remotefilename=str_replace("\\","/",$remotefilename);
	$remotefile[$remotefilename]=$remotefilehash;
}

/* Local Hash Table */
unset($response);
$response=file_get_contents("hash.dat");
$response=explode("\r\n",$response);
foreach($response as $value){
	unset($localfilename,$localfilehash);
	$value=explode("  ",$value);
	$localfilehash=$value[0];
	unset($value[0]);
	$localfilename=implode("  ",$value);
	$localfilename=str_replace("\\","/",$localfilename);
	$localfile[$localfilename]=$localfilehash;
}

/* Proceed Hash Checking */
foreach($remotefile as $remotekey=>$remotevalue){
	if($remotevalue != $localfile[$remotekey]){
		if(preg_match('/\.\/data\/gfq\.pubkey/',$remotekey)){
			if(file_exists('data/gfq.pubkey')){
				continue; //SKIP, FOR PROTECT THE PUBLIC KEY
			}
		}
		
		if(! preg_match('/\.\/\.svn\//',$remotekey)){
			if(! in_array($remotekey,$ignore)){
				update($remotekey,$remotevalue);
			}
		}
	}
}

echo "\r\n";

/* Hosts */
echo "Grabbing host file from smarthosts:\r\n";
@unlink("data/host");
$googleip=array();
$host=request("GET /svn/trunk/hosts HTTP/1.1\r\nHost:{host}\r\nConnection: close\r\n\r\n","smarthosts.googlecode.com");
$host=explode("\r\n",$host);
foreach($host as $hostkey=>$hoststring){
	//talk.google.com is special case. We CANNOT use it as G-Server
	if(preg_match('/(.*?)\ttalk\.google\.com$/',$hoststring,$hostmatch)){
	}elseif(preg_match('/(.*?)\t.*?\.google\.com$/',$hoststring,$hostmatch)){
		if(filter_var($hostmatch[1],FILTER_VALIDATE_IP)){
			$googleip[]=$hostmatch[1];
		}
	}
}

if(count($googleip)){
	$googleip=array_unique($googleip);
	file_put_contents("data/host",implode("\r\n",$googleip));
	echo " GOOGLE-IP=".implode(",",$googleip)."\r\n";
}else{
	//
}

echo "\r\n";
?>